﻿using System;
using System.Collections.Generic;
using System.Text;
using MySql.Data.MySqlClient;
using System.Data;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Elight.Repository.Interfaces;
using Elight.Infrastructure.Settings;
using Elight.Infrastructure.Ioc;
using Dapper;
using Dapper.Contrib.Extensions;

namespace Elight.Repository
{
    public partial class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class
    {
        internal ConnectionStringsSetting ConnectionStrings { get; }

        public BaseRepository()
        {
            ConnectionStrings = ServiceLocator.GetService<IOptions<AppSettings>>().Value.ConnectionStrings;
        }

        //public BaseRepository(IOptions<AppSettings> appSettings)
        //{
        //    ConnectionStrings = appSettings.Value.ConnectionStrings;
        //}

        public IDbConnection OpenSharedConnection(string connectionString = null)
        {
            IDbConnection conn = null;
            if (string.IsNullOrEmpty(connectionString))
            {
                conn = new MySqlConnection(ConnectionStrings.Basic);
            }
            else
            {
                conn = new MySqlConnection(connectionString);
            }
            if (conn.State != ConnectionState.Open)
            {
                conn.Open();
            }
            return conn;
        }

        public TEntity Get(int id)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return conn.Get<TEntity>(id);
            }
        }

        public async Task<TEntity> GetAsync(int id)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return await conn.GetAsync<TEntity>(id);
            }
        }

        public IEnumerable<TEntity> GetAll()
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return conn.GetAll<TEntity>();
            }
        }

        public async Task<IEnumerable<TEntity>> GetAllAsync()
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return await conn.GetAllAsync<TEntity>();
            }
        }

        public long Insert(TEntity entity)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return conn.Insert(entity);
            }
        }

        public async Task<long> InsertAsync(TEntity entity)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return await conn.InsertAsync(entity);
            }
        }

        public long Insert(List<TEntity> entities)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return conn.Insert(entities);
            }
        }

        public async Task<long> InsertAsync(List<TEntity> entities)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                var trans = conn.BeginTransaction();
                try
                {
                    long row = await conn.InsertAsync(entities, trans);
                    trans.Commit();
                    return row;
                }
                catch (Exception)
                {
                    trans.Rollback();
                    throw;
                }
            }
        }

        public bool Update(TEntity entity)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return conn.Update(entity);
            }
        }

        public async Task<bool> UpdateAsync(TEntity entity)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return await conn.UpdateAsync(entity);
            }
        }

        public bool Update(List<TEntity> entities)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return conn.Update(entities);
            }
        }

        public async Task<bool> UpdateAsync(List<TEntity> entities)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                var trans = conn.BeginTransaction();
                try
                {
                    bool isSuccess = await conn.UpdateAsync(entities, trans);
                    trans.Commit();
                    return isSuccess;
                }
                catch (Exception)
                {
                    trans.Rollback();
                    throw;
                }
            }
        }

        public bool Delete(TEntity entity)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return conn.Delete(entity);
            }
        }

        public async Task<bool> DeleteAsync(TEntity entity)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return await conn.DeleteAsync(entity);
            }
        }

        public bool DeleteAll()
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return conn.DeleteAll<TEntity>();
            }
        }

        public async Task<bool> DeleteAllAsync()
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                return await conn.DeleteAllAsync<TEntity>();
            }
        }

        public bool Delete(int id)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                int row = conn.Execute($"delete from {typeof(TEntity).Name} where Id=@id", new { @id = id });
                return row > 0 ? true : false;
            }
        }

        public async Task<bool> DeleteAsync(int id)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                int row = await conn.ExecuteAsync($"delete from {typeof(TEntity).Name} where Id=@id", new { @id = id });
                return row > 0 ? true : false;
            }
        }

        public bool DeleteSoft(int id)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                int row = conn.Execute($"update {typeof(TEntity).Name} set IsDelete=1 where Id=@id", new { @id = id });
                return row > 0 ? true : false;
            }
        }

        public async Task<bool> DeleteSoftAsync(int id)
        {
            using (IDbConnection conn = OpenSharedConnection())
            {
                int row = await conn.ExecuteAsync($"update {typeof(TEntity).Name} set IsDelete=1 where Id=@id", new { @id = id });
                return row > 0 ? true : false;
            }
        }
    }
}
